# ModelForm 验证
from web import models
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.conf import settings
from utils.sms.send import send_sms_single
import random
from django_redis import get_redis_connection
from utils.mds import MD5

from web.Forms.bootstrap import BootStrap
from django.db.models import Q


# 注册modeForm 渲染+校验
class RegisterModelForm(BootStrap, forms.ModelForm):
    password = forms.CharField(label='密码',
                               max_length=64,
                               min_length=3,
                               error_messages={
                                   'max_length': '密码长度不能大于64位',
                                   'min_length': '密码长度不能小于3位'
                               },
                               widget=forms.PasswordInput(
                                   attrs={'placeholder': '请再次输入密码'}))

    re_password = forms.CharField(label='确认密码',
                                  max_length=64,
                                  min_length=3,
                                  error_messages={
                                      'max_length': '密码长度不能大于64位',
                                      'min_length': '密码长度不能小于3位'
                                  },
                                  widget=forms.PasswordInput(
                                  ))

    telephone = forms.CharField(label='手机号码', validators=[RegexValidator(r'^1[3-9][0-9]{9}$', '手机号格式错误'), ], )

    code = forms.CharField(label='验证码',
                           widget=forms.TextInput(
                           ))

    class Meta:
        model = models.UserIfo
        fields = ['username', 'password', 're_password', 'email', 'telephone', 'code']

    def clean_username(self):
        username = self.cleaned_data['username']
        exists = models.UserIfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已经存在，请选择一个新的用户名')
        return username

    def clean_password(self):
        # 需要md5加密
        password = self.cleaned_data['password']
        password = MD5(password)
        return password

    def clean_re_password(self):
        re_password = MD5(self.cleaned_data['re_password'])

        password = self.cleaned_data.get('password')
        if not password:
            return re_password

        if not password == re_password:
            raise ValidationError('两次输入的密码不一致')
        return re_password

    def clean_telephone(self):
        telephone = self.cleaned_data['telephone']
        exists = models.UserIfo.objects.filter(telephone=telephone).exists()
        if exists:
            raise ValidationError('当前手机号已经注册')
        return telephone

    def clean_code(self):
        # 获取前端传过来的code
        code = self.cleaned_data['code']
        # 获取当前手机号
        telephone = self.cleaned_data.get('telephone')
        if not telephone:
            return code

        # 获取redis的code
        conn = get_redis_connection()
        # bys--utf-8 需要decode
        redis_code = conn.get(telephone).decode('utf-8')
        if not redis_code:
            raise ValidationError('验证码失效，请重新发送')
        # 转码与前端传过来的code进行比较
        if not code.strip() == redis_code:
            raise ValidationError('验证码错误')
        return code


# 发送短信验证码的form 校验+发送短信
class SendSmsForm(forms.Form):
    telephone = forms.CharField(label='手机号码', validators=[RegexValidator(r'^1[3-9][0-9]{9}$', '手机号格式错误'), ], )

    def __init__(self, request, *args, **kwargs):
        super(SendSmsForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_telephone(self):
        '''检验手机号'''
        telephone = self.cleaned_data['telephone']
        # print(self.cleaned_data)

        # 检验是否有模板
        tpl = self.request.GET.get('tpl')
        tpl_id = settings.PYTHON_SMS_TEMPLATE.get(tpl)
        if not tpl_id:
            raise ValidationError('模板错误，疑似爬虫！！已向后台发送异常请求')

        if tpl == 'login':
            pass
        elif tpl == 'register':
            # 检验手机号是否存在
            exists = models.UserIfo.objects.filter(telephone=telephone).exists()
            if exists:
                raise ValidationError('手机号已经存在，每个手机号只能注册一个账号')
        else:
            pass

        # 发送短信
        code = random.randrange(1000, 9999)
        sms = send_sms_single(telephone, tpl_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError('发送失败,{}'.format(sms['errmsg']))
        # 存储redis中
        conn = get_redis_connection()
        conn.set(telephone, code, ex=9999999999)
        return telephone


# 短信登录login 渲染+校验
class LoginForm(BootStrap, forms.Form):
    telephone = forms.CharField(label='手机号码', validators=[RegexValidator(r'^1[3-9][0-9]{9}$', '手机号格式错误'), ], )

    code = forms.CharField(label='验证码',
                           widget=forms.TextInput(
                           ))

    def clean_telephone(self):
        # 获取手机号以后将进行数据库查询，

        telephone = self.cleaned_data['telephone']
        exists = models.UserIfo.objects.filter(telephone=telephone).exists()
        if not exists:
            raise ValidationError('手机号不存在')

        return telephone

    def clean_code(self):

        # 获取前端code与redis code进行验证对比
        # 获取前端传过来的code
        code = self.cleaned_data['code']
        # 获取当前手机号
        telephone = self.cleaned_data.get('telephone')
        if not telephone:
            return code

        # 获取redis的code
        conn = get_redis_connection()
        # bys--utf-8 需要decode
        redis_code = conn.get(telephone).decode('utf-8')
        if not redis_code:
            raise ValidationError('验证码失效，请重新发送')
        # 转码与前端传过来的code进行比较
        if not code.strip() == redis_code:
            raise ValidationError('验证码错误')
        return code


# 多方式登录
class LoginCodeForm(BootStrap, forms.Form):
    username = forms.CharField(label='用户名或手机号或邮箱登录')
    # render_value=True 密码框不刷新
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='验证码')

    def __init__(self, request, *args, **kwargs):
        super(LoginCodeForm, self).__init__(*args, **kwargs)
        self.request = request

    def clean_username(self):
        username = self.cleaned_data.get('username')
        exists = models.UserIfo.objects.filter(
            Q(username=username) | Q(telephone=username) | Q(email=username)).first()
        if not exists:
            raise ValidationError('账号错误')
        return username

    def clean_password(self):
        password = MD5(self.cleaned_data.get('password'))
        exists = models.UserIfo.objects.filter(password=password).exists()
        if not exists:
            raise ValidationError('密码错误')
        return password

    def clean_code(self):
        # 获取前端的code
        code = self.cleaned_data.get('code')
        # 获取session的code
        img_code = self.request.session.get('img_code')
        # 进行校验
        if not code.lower().strip() == img_code.lower().strip():
            raise ValidationError('验证码错误')
        return code
